package smtpclient

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

// SMTPClient SMTP客户端
type SMTPClient struct {
	conn      net.Conn
	reader    *bufio.Reader
	writer    *bufio.Writer
	host      string
	port      int
	useTLS    bool
	tlsConfig *tls.Config
	heloHost  string
	username  string
	password  string
}

// NewSMTPClient 创建新的SMTP客户端
func NewSMTPClient(host string, port int, useTLS bool) *SMTPClient {
	return &SMTPClient{
		host:   host,
		port:   port,
		useTLS: useTLS,
		tlsConfig: &tls.Config{
			InsecureSkipVerify: true, // 在生产环境中应该设置为 false
		},
		heloHost: host, // 默认使用服务器主机名
	}
}

// SetHeloHost 设置HELO主机名
func (c *SMTPClient) SetHeloHost(host string) {
	c.heloHost = host
}

// SetAuth 设置认证信息
func (c *SMTPClient) SetAuth(username, password string) {
	c.username = username
	c.password = password
}

// Connect 连接到SMTP服务器
func (c *SMTPClient) Connect() error {
	addr := net.JoinHostPort(c.host, strconv.Itoa(c.port))
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return fmt.Errorf("连接服务器失败: %v", err)
	}
	c.conn = conn
	c.reader = bufio.NewReader(conn)
	c.writer = bufio.NewWriter(conn)

	// 读取服务器欢迎消息
	_, err = c.readResponse()
	if err != nil {
		return fmt.Errorf("读取欢迎消息失败: %v", err)
	}

	return nil
}

// StartTLS 启动TLS连接
func (c *SMTPClient) StartTLS() error {
	// 发送STARTTLS命令
	err := c.sendCommand("STARTTLS")
	if err != nil {
		return fmt.Errorf("发送STARTTLS命令失败: %v", err)
	}

	// 升级连接为TLS
	tlsConn := tls.Client(c.conn, c.tlsConfig)
	err = tlsConn.Handshake()
	if err != nil {
		return fmt.Errorf("TLS握手失败: %v", err)
	}

	c.conn = tlsConn
	c.reader = bufio.NewReader(tlsConn)
	c.writer = bufio.NewWriter(tlsConn)

	return nil
}

// Auth 进行SMTP认证
func (c *SMTPClient) Auth() error {
	if c.username == "" || c.password == "" {
		return nil // 没有认证信息，跳过认证
	}

	// 尝试 AUTH LOGIN
	err := c.sendCommand("AUTH LOGIN")
	if err != nil {
		// 如果 AUTH LOGIN 失败，尝试 AUTH PLAIN
		err = c.sendCommand("AUTH PLAIN")
		if err != nil {
			return fmt.Errorf("认证失败: %v", err)
		}
		// AUTH PLAIN
		auth := base64.StdEncoding.EncodeToString([]byte("\x00" + c.username + "\x00" + c.password))
		err = c.sendCommand(auth)
	} else {
		// AUTH LOGIN
		username := base64.StdEncoding.EncodeToString([]byte(c.username))
		err = c.sendCommand(username)
		if err != nil {
			return fmt.Errorf("发送用户名失败: %v", err)
		}
		password := base64.StdEncoding.EncodeToString([]byte(c.password))
		err = c.sendCommand(password)
	}

	if err != nil {
		return fmt.Errorf("认证失败: %v", err)
	}

	return nil
}

// writeMessage 处理并发送邮件内容，包括点转义和换行符处理
func (c *SMTPClient) writeMessage(message []byte) error {
	var buf bytes.Buffer
	scanner := bufio.NewScanner(bytes.NewReader(message))
	scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		if atEOF && len(data) == 0 {
			return 0, nil, nil
		}

		// 查找换行符
		if i := bytes.IndexAny(data, "\r\n"); i >= 0 {
			// 找到换行符
			if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
				return i + 2, data[:i], nil
			}
			return i + 1, data[:i], nil
		}

		if atEOF {
			return len(data), data, nil
		}
		return 0, nil, nil
	})

	for scanner.Scan() {
		line := scanner.Bytes()
		// 处理点转义
		if len(line) > 0 && line[0] == '.' {
			buf.WriteByte('.')
		}
		buf.Write(line)
		buf.WriteString("\r\n")
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("处理邮件内容失败: %v", err)
	}

	// 一次性写入所有内容
	_, err := c.writer.Write(buf.Bytes())
	if err != nil {
		return fmt.Errorf("发送邮件内容失败: %v", err)
	}
	return c.writer.Flush()
}

// SendMail 发送邮件
func (c *SMTPClient) SendMail(from string, to []string, message []byte) error {
	// 发送EHLO命令
	err := c.sendCommand(fmt.Sprintf("EHLO %s", c.heloHost))
	if err != nil {
		return fmt.Errorf("发送EHLO命令失败: %v", err)
	}

	// 如果需要TLS，启动TLS
	if c.useTLS {
		err = c.StartTLS()
		if err != nil {
			return fmt.Errorf("启动TLS失败: %v", err)
		}
	}

	// 如果需要认证，进行认证
	if c.username != "" && c.password != "" {
		err = c.Auth()
		if err != nil {
			return fmt.Errorf("认证失败: %v", err)
		}
	}

	// 发送MAIL FROM命令
	err = c.sendCommand(fmt.Sprintf("MAIL FROM:<%s>", from))
	if err != nil {
		return fmt.Errorf("发送MAIL FROM命令失败: %v", err)
	}

	// 发送RCPT TO命令
	for _, recipient := range to {
		err = c.sendCommand(fmt.Sprintf("RCPT TO:<%s>", recipient))
		if err != nil {
			return fmt.Errorf("发送RCPT TO命令失败: %v", err)
		}
	}

	// 发送DATA命令
	err = c.sendCommand("DATA")
	if err != nil {
		return fmt.Errorf("发送DATA命令失败: %v", err)
	}

	// 发送邮件内容
	if err := c.writeMessage(message); err != nil {
		return err
	}

	// 发送结束标记
	err = c.sendCommand(".")
	if err != nil {
		return fmt.Errorf("发送结束标记失败: %v", err)
	}

	return nil
}

// Quit 关闭连接
func (c *SMTPClient) Quit() error {
	err := c.sendCommand("QUIT")
	if err != nil {
		return fmt.Errorf("发送QUIT命令失败: %v", err)
	}
	return c.conn.Close()
}

// sendCommand 发送命令并读取响应
func (c *SMTPClient) sendCommand(cmd string) error {
	_, err := c.writer.WriteString(cmd + "\r\n")
	if err != nil {
		return err
	}
	err = c.writer.Flush()
	if err != nil {
		return err
	}
	_, err = c.readResponse()
	return err
}

// readResponse 读取服务器响应
func (c *SMTPClient) readResponse() (string, error) {
	response, err := c.reader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(response), nil
}

// GenerateEmail 生成邮件内容
func GenerateEmail(from string, to []string, subject string, body string) []byte {
	var message strings.Builder

	// 添加邮件头
	message.WriteString(fmt.Sprintf("From: %s\r\n", from))
	message.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(to, ", ")))
	message.WriteString(fmt.Sprintf("Subject: %s\r\n", subject))
	message.WriteString("Date: " + time.Now().Format(time.RFC1123Z) + "\r\n")
	message.WriteString("MIME-Version: 1.0\r\n")
	message.WriteString("Content-Type: text/plain; charset=UTF-8\r\n")
	message.WriteString("\r\n")

	// 添加邮件正文
	message.WriteString(body)
	message.WriteString("\r\n.\r\n")

	return []byte(message.String())
}

// Close 关闭连接
func (c *SMTPClient) Close() error {
	if c.conn != nil {
		return c.conn.Close()
	}
	return nil
}
